package com.lx.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * @author lx
 */
@Configuration
@EnableMethodSecurity  // 开启基于方法的授权（只需在controller层设置，注释掉所有关于request授权的内容）
public class WebSecurityConfig {
    /* 基于内存的用户认证
    @Bean
    public UserDetailsService userDetailsService() {
        // 创建基于内存的用户信息管理器
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        // 使用manager管理UserDetail对象
        manager.createUser(
                // 创建UserDetail对象，用于管理用户名、密码、角色、权限等信息
                User
                        .withDefaultPasswordEncoder()
                        .username("liuXiong") //自定义用户名
                        .password("password") //自定义密码
                        .build()
        );
        return manager;
    }*/

    /*// 基于数据库的用户认证，由于这里只创建了一个管理器对象，还可以通过在DBUserDetailsManager类上添加@Component注解来实现
    @Bean
    public UserDetailsService userDetailsService() {
        DBUserDetailsManager manager = new DBUserDetailsManager();
        return manager;
    }*/

    // 默认配置
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        //authorizeRequests()：开启授权保护
        //anyRequest()：对所有请求开启授权保护
        //authenticated()：已认证请求会自动被授权
        http.authorizeRequests(
                authorize -> authorize
                        /*基于基于request的授权
                        //基于权限分配
                        //具有USER_LIST权限的用户可以访问/user/list
                        .requestMatchers("/user/list").hasAuthority("USER_LIST")
                        //具有USER_ADD权限的用户可以访问/user/add
                        .requestMatchers("/user/add").hasAuthority("USER_ADD")*/

                        /*// 基于角色分配
                        //具有管理员角色的用户可以访问/user/**
                        .requestMatchers("/user/**").hasRole("ADMIN")*/
                        //对所有请求开启授权保护
                        .anyRequest()
                        //已认证的请求会被自动授权
                        .authenticated())
            //.formLogin(withDefaults())//表单授权方式，withDefaults()：默认的表单
            // 自定义表单
            .formLogin(form -> {
                form
                        .loginPage("/login").permitAll() //登录页面无需授权即可访问
                        .usernameParameter("username") //自定义表单用户名参数，默认是username
                        .passwordParameter("password") //自定义表单密码参数，默认是password
                        .failureUrl("/login?error") //登录失败的返回地址
                        .successHandler(new MyAuthenticationSuccessHandler()) //认证成功时的处理
                        .failureHandler(new MyAuthenticationFailureHandler()) //认证失败时的处理
                ;
            })
            .httpBasic(withDefaults());//基本授权方式

        //注销成功时的处理
        http.logout(logout -> {
            logout.logoutSuccessHandler(new MyLogoutSuccessHandler());
        });

        //请求未认证、授权的处理
        http.exceptionHandling(exception  -> {
            exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());  //未认证
            exception.accessDeniedHandler(new MyAccessDeniedHandler());    //未授权
        });

        //会话管理，后登录的账号会使先登录的账号失效
        http.sessionManagement(session -> {
            session
                    .maximumSessions(1)
                    .expiredSessionStrategy(new MySessionInformationExpiredStrategy());
        });


        //关闭csrf攻击防御
        http.csrf((csrf) -> {
            csrf.disable();
        });

        //跨域
        http.cors(withDefaults());

        return http.build();
    }
}
